﻿//-----------------------------------------------------------------------
// <copyright file="CameraTool.cs" company="Nathan Miller">
// Copyright (c) Nathan Miller.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
//-----------------------------------------------------------------------
namespace TileTool.Base.Tool.Camera
{
    using TileTool.Base.Editor.Tool.Camera;
    using TileTool.Common.Math;
    using TileTool.Editor.Tool.Camera;
    using TileTool.Editor.Tool.Scene;
    using TileTool.Input;
    using TileTool.Input.Focus;
    using TileTool.Input.Keyboard;
    using TileTool.Input.Mouse;
    using TileTool.Settings;
    using TileTool.Tool;

    /// <summary>
    /// Simple camera tool.
    /// </summary>
    public class CameraTool : CameraToolBase
    {
        #region Fields - Private

        /// <summary>
        /// True if the alt key is down.
        /// </summary>
        private bool altDown = false;

        /// <summary>
        /// True if we are dragging with the mouse button down.
        /// </summary>
        private bool dragging = false;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public CameraTool()
        {
            this.Mode = ToolMode.Permanent;
        }

        #endregion

        #region Methods - Protected

        /// <summary>
        /// Handle key down input data.
        /// </summary>
        /// <param name="sceneInputData">Scene input data.</param>
        /// <param name="inputData">Input data to handle.</param>
        /// <returns>Returns if the input data was handled or not.</returns>
        protected override InputHandled HandleKeyDown(SceneToolInputData sceneInputData, KeyInputData inputData)
        {
            if (inputData.Key != InputKey.Menu)
            {
                return InputHandled.No;
            }

            this.altDown = true;

            return InputHandled.Yes;
        }

        /// <summary>
        /// Handle key up input data.
        /// </summary>
        /// <param name="sceneInputData">Scene input data.</param>
        /// <param name="inputData">Input data to handle.</param>
        /// <returns>Returns if the input data was handled or not.</returns>
        protected override InputHandled HandleKeyUp(SceneToolInputData sceneInputData, KeyInputData inputData)
        {
            if (inputData.Key != InputKey.Menu)
            {
                return InputHandled.No;
            }

            this.altDown = false;

            return InputHandled.Yes;
        }

        /// <summary>
        /// Handle mouse move input data.
        /// </summary>
        /// <param name="sceneInputData">Scene input data.</param>
        /// <param name="inputData">Input data to handle.</param>
        /// <returns>Returns if the input data was handled or not.</returns>
        protected override InputHandled HandleMouseMove(SceneToolInputData sceneInputData, MouseMoveInputData inputData)
        {
            if (!this.altDown)
            {
                return InputHandled.No;
            }

            if (!this.dragging)
            {
                return InputHandled.No;
            }

            CameraToolSettings settings = SettingsSystem.Get<CameraToolSettings>();

            Vector2D newPos = Camera.Position;

            if (settings.InvertX)
            {
                newPos.x = newPos.x + inputData.Delta.x;
            }
            else
            {
                newPos.x = newPos.x - inputData.Delta.x;
            }

            if (settings.InvertY)
            {
                newPos.y = newPos.y + inputData.Delta.y;
            }
            else
            {
                newPos.y = newPos.y - inputData.Delta.y;
            }

            Camera.Position = newPos;

            return InputHandled.Yes;
        }

        /// <summary>
        /// Handle left mouse button down.
        /// </summary>
        /// <param name="sceneInputData">Scene input data.</param>
        /// <param name="inputData">Input data to handle.</param>
        /// <returns>Returns if the input data was handled or not.</returns>
        protected override InputHandled HandleLeftMouseButtonDown(SceneToolInputData sceneInputData, MouseButtonInputData inputData)
        {
            if (!this.altDown)
            {
                return InputHandled.No;
            }

            this.dragging = true;

            return InputHandled.Yes;
        }

        /// <summary>
        /// Handle left mouse button up.
        /// </summary>
        /// <param name="sceneInputData">Scene input data.</param>
        /// <param name="inputData">Input data to handle.</param>
        /// <returns>Returns if the input data was handled or not.</returns>
        protected override InputHandled HandleLeftMouseButtonUp(SceneToolInputData sceneInputData, MouseButtonInputData inputData)
        {
            if (!this.dragging)
            {
                return InputHandled.No;
            }

            this.dragging = false;

            return InputHandled.Yes;
        }

        /// <summary>
        /// Handle lost focus input data.
        /// </summary>
        /// <param name="sceneInputData">Scene input data.</param>
        /// <param name="inputData">Input data to handle.</param>
        /// <returns>Returns if the input data was handled or not.</returns>
        protected override InputHandled HandleLostFocus(SceneToolInputData sceneInputData, FocusInputData inputData)
        {
            this.dragging = false;
            this.altDown = false;

            return InputHandled.No;
        }

        #endregion
    }
}
